﻿using System;
using System.Threading.Tasks;

using Windows.UI.Xaml;

using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;

using Uhimania.Libraries.Test;

using Uhimania.Libraries.Windows.Interactivity;

namespace Windows.InteractivityTest
{
    [TestClass]
    public class AttachableCollectionTest
    {
        #region AssociatedObject

        #region 正常ケース
        [TestMethod]
        public async Task AssociatedObject_正常ケース()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var mock = new Mock();
                var collection = new MockCollection();

                collection.Attach(mock);
                collection.AssociatedObject.Is(mock);
                collection.attach.Is(true);

                collection.Detach();
                collection.AssociatedObject.IsNull();
                collection.detach.Is(true);
            });
        }
        #endregion

        #endregion

        #region CollectionChanged

        #region Add
        [TestMethod]
        public async Task CollectionChanged_Add()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var associated = new Mock();
                var collection = new MockCollection();
                collection.AssociatedObject = associated;

                var item1 = new Mock();
                var item2 = new Mock();

                collection.Add(item1);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.IsNull();

                collection.Insert(0, item2);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.Is(associated);
            });
        }
        #endregion

        #region Remove
        [TestMethod]
        public async Task CollectionChanged_Remove()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var associated = new Mock();
                var collection = new MockCollection();
                collection.AssociatedObject = associated;

                var item1 = new Mock();
                var item2 = new Mock();

                collection.Add(item1);
                collection.Add(item2);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.Is(associated);

                collection.Remove(item1);
                item1.AssociatedObject.IsNull();
                item2.AssociatedObject.Is(associated);

                collection.RemoveAt(0);
                item1.AssociatedObject.IsNull();
                item2.AssociatedObject.IsNull();
            });
        }
        #endregion

        #region Replace
        [TestMethod]
        public async Task CollectionChanged_Replace()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var associated = new Mock();
                var collection = new MockCollection();
                collection.AssociatedObject = associated;

                var item1 = new Mock();
                var item2 = new Mock();

                collection.Add(item1);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.IsNull();

                collection[0] = item2;
                item1.AssociatedObject.IsNull();
                item2.AssociatedObject.Is(associated);
            });
        }
        #endregion

        #region Move
        [TestMethod]
        public async Task CollectionChanged_Move()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var associated = new Mock();
                var collection = new MockCollection();
                collection.AssociatedObject = associated;

                var item1 = new Mock();
                var item2 = new Mock();
                var item3 = new Mock();

                collection.Add(item1);
                collection.Add(item2);
                collection.Add(item3);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.Is(associated);
                item3.AssociatedObject.Is(associated);

                collection.Move(0, 2);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.Is(associated);
                item3.AssociatedObject.Is(associated);
            });
        }
        #endregion

        #region Reset
        [TestMethod]
        public async Task CollectionChanged_Reset()
        {
            await UiTestHelper.ExecuteOnUiThread(() =>
            {
                var associated = new Mock();
                var collection = new MockCollection();
                collection.AssociatedObject = associated;

                var item1 = new Mock();
                var item2 = new Mock();
                var item3 = new Mock();

                collection.Add(item1);
                collection.Add(item2);
                collection.Add(item3);
                item1.AssociatedObject.Is(associated);
                item2.AssociatedObject.Is(associated);
                item3.AssociatedObject.Is(associated);

                collection.Clear();
                item1.AssociatedObject.IsNull();
                item2.AssociatedObject.IsNull();
                item3.AssociatedObject.IsNull();
            });
        }
        #endregion

        #endregion

        #region Mock

        private class Mock : DependencyObject, IAttachedObject
        {
            public DependencyObject AssociatedObject { get; set; }

            public void Attach(DependencyObject associatedObject)
            {
                this.AssociatedObject = associatedObject;
            }

            public void Detach()
            {
                this.AssociatedObject = null;
            }
        }

        private class MockCollection : AttachableCollection<Mock>
        {
            public bool attach = false;
            protected override void OnAttached()
            {
                this.attach = true;
            }

            public bool detach = false;
            protected override void OnDetaching()
            {
                this.detach = true;
            }

            protected override void ItemAdded(Mock item)
            {
                item.Attach(this.AssociatedObject);
            }

            protected override void ItemRemoved(Mock item)
            {
                item.Detach();
            }
        }

        #endregion
    }
}
